package com.kgc.rb.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSONObject;
import com.kgc.rb.common.tools.ActiveMQTools;
import com.kgc.rb.common.tools.Constants;
import com.kgc.rb.common.tools.EmptyUtils;
import com.kgc.rb.common.tools.IdWorker;
import com.kgc.rb.dto.RbGoodsMessage;
import com.kgc.rb.dto.RbResult;
import com.kgc.rb.dto.vo.GoodsVO;
import com.kgc.rb.exception.GoodsException;
import com.kgc.rb.pojo.QgGoods;
import com.kgc.rb.pojo.QgGoodsTempStock;
import com.kgc.rb.pojo.QgOrder;
import com.kgc.rb.pojo.QgUser;
import com.kgc.rb.service.LocalGoodsService;
import com.kgc.rb.service.QgGoodsService;
import com.kgc.rb.service.QgGoodsTempStockService;
import com.kgc.rb.service.QgOrderService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class LocalGoodsServiceImpl implements LocalGoodsService {

    @Reference(check = false)
    private QgGoodsService qgGoodsService;
    @Reference(check = false)
    private QgGoodsTempStockService goodsTempStockService;
    @Reference(check = false)
    private QgOrderService qgOrderService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ActiveMQTools activeMQTools;

    @Override
    public RbResult queryGoodsById(String goodsId) throws Exception {
        GoodsVO goods = null;
        //1.先去redis中查询是否有该商品存在，如果有就不去数据库中查询，
        goods = (GoodsVO) redisTemplate.opsForValue().get(Constants.GOODS_PREFIX + goodsId);
        //2. 如果没有在去数据库中查询然后将商品的详细信息存储在redis中
        if (goods != null) {
            return RbResult.ok(goods);
        }
        //如果代码能走到这里说明，redis中没有查询到该商品的信息，就走数据库去进行查询
        //3.根据商品编号在商品信息表qg_goods查询商品信息
        QgGoods qgGoods = qgGoodsService.getQgGoodsById(goodsId);
        //4.根据商品编号在实时库存表qg_goods_temp_stock中查询已抢购的合法数量
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("goodsId", goodsId);
        params.put("active", 1);
        Integer ssStock = goodsTempStockService.getQgGoodsTempStockCountByMap(params);
        //5.计算剩余库存=原始库存-实时库存[就是第二步中查询出来的数据]
        Integer currentStock = qgGoods.getStock() - ssStock;
        //考虑使用哪一个实体类封装数据到页面上？我们需要自己取dto中新建一个GoodsVo对象来封装数据
        goods = new GoodsVO();
        BeanUtils.copyProperties(qgGoods, goods);
        goods.setCurrentStock(currentStock);
        //6.将数据存储到redis中
        redisTemplate.opsForValue().set(Constants.GOODS_PREFIX + goodsId, goods);
        return RbResult.ok(goods);
    }

    /**
     * 发送用户抢购商品的消息到ActiveMQ中去
     *
     * @param token   用户登录的凭证
     * @param goodsId 抢购商品的编号
     * @return
     */
    @Override
    public RbResult sendQgGoodsMessage(String token, String goodsId) throws Exception {
        //1. 发送哪一个用户抢购的哪一个商品到消息中间件中去
        //1.根据token获取等的用户的信息
        QgUser qgUser = (QgUser) redisTemplate.opsForValue().get(token);
        String userId = qgUser.getId();
        // 用户的信息和商品的信息
        RbGoodsMessage rbGoodsMessage = new RbGoodsMessage();
        rbGoodsMessage.setUserId(userId);
        rbGoodsMessage.setGoodsId(goodsId);
        rbGoodsMessage.setCreateDate(new Date());
        activeMQTools.sendQueueMessage(Constants.ActiveMQMessage.MESSAGE_NAME, rbGoodsMessage);
        //2.相应客户端
        return RbResult.ok();
    }

    /**
     * 刷新用户抢购商品的结果的处理方法
     *
     * @param token
     * @param goodsId
     * @return
     */
    @Override
    public RbResult flushUserRbGoodsResult(String token, String goodsId) {
        //1.根据token获取等的用户的信息
        QgUser qgUser = (QgUser) redisTemplate.opsForValue().get(token);
        //根据key:U_Goods:1_1取出用户抢购商品的状态
        String status = (String) redisTemplate.opsForValue().get(Constants.USER_RB_GOODS + qgUser.getId() + "_" + goodsId);
        if (EmptyUtils.isEmpty(status)) {//说明该用户抢购商品的线程还在排队
            return RbResult.build(GoodsException.GOODS_IS_GETTING.getCode(), GoodsException.GOODS_IS_GETTING.getMessage());
        } else if (status.equals(Constants.UserRbGoodsStatus.FAILD)) {//抢购失败
            return RbResult.build(GoodsException.GOODS_STOCK_INSUFFICIENT.getCode(), GoodsException.GOODS_STOCK_INSUFFICIENT.getMessage());
        } else if (status.equals(Constants.UserRbGoodsStatus.REPEAT)) {//重复抢购
            return RbResult.build(GoodsException.REPEAT_BUY.getCode(), GoodsException.REPEAT_BUY.getMessage());
        } else {//抢购成功
            return RbResult.build(GoodsException.BUY_SUCCESS.getCode(), GoodsException.BUY_SUCCESS.getMessage());
        }
    }

    /**
     * 处理消息中间件中用户抢购商品的请求
     *
     * @param rbGoodsMessage 消息中间件中存储的对象
     */
    @JmsListener(destination = Constants.ActiveMQMessage.MESSAGE_NAME)
    private void handleActiveMQUserRbGoods(RbGoodsMessage rbGoodsMessage) throws Exception {
        String userId = rbGoodsMessage.getUserId();
        String goodsId = rbGoodsMessage.getGoodsId();
        while (!redisTemplate.opsForValue().setIfAbsent(Constants.LOCK_PREFIX + goodsId, Constants.LOCK_EXPIRE_TIME)) {
            Thread.sleep(3);
        }
        //2.判断该用户是否抢购过商品，如果用户有抢购未支付的或者是已经支付成功的记录，则该用户不能够抢购
        String userIsRbGoodsJsonStr = (String) redisTemplate.opsForValue().get(Constants.USER_RB_GOODS + userId + "_" + goodsId);
        if (EmptyUtils.isNotEmpty(userIsRbGoodsJsonStr)
                && Constants.UserRbGoodsStatus.SUCCESS.equals(userIsRbGoodsJsonStr)) {//说明用户已经抢购过商品了
            redisTemplate.opsForValue().set(Constants.USER_RB_GOODS + userId + "_" + goodsId, Constants.UserRbGoodsStatus.REPEAT);
            //释放锁
            redisTemplate.opsForValue().getOperations().delete(Constants.LOCK_PREFIX + goodsId);
            return;
        }
        //如果代码能走到这里说明该用户没有抢购过该商品
        //3.判断库存是否大于0，如果大于0则进入抢购环节
        GoodsVO goodsVO = (GoodsVO) redisTemplate.opsForValue().get(Constants.GOODS_PREFIX + goodsId);
        if (!(goodsVO.getCurrentStock() > 0)) {//库存不大于0
            //更新redis中哪一个用户抢购哪一个商品的状态
            redisTemplate.opsForValue().set(Constants.USER_RB_GOODS + userId + "_" + goodsId, Constants.UserRbGoodsStatus.FAILD);
            //释放锁
            redisTemplate.opsForValue().getOperations().delete(Constants.LOCK_PREFIX + goodsId);
            return;
        }
        //如果代码能走到这里说明库存也充足
        //4.跟新库存：向实时库存表中插入数据库qg_goods_temp_stock
        String stockId = addTempStock(goodsId, userId);
        //减去库存
        goodsVO.setCurrentStock(goodsVO.getCurrentStock() - 1);
        redisTemplate.opsForValue().set(Constants.GOODS_PREFIX + goodsId, goodsVO);
        //将哪一个用户抢购到哪一个商品的标识存入reids中
        redisTemplate.opsForValue().set(Constants.USER_RB_GOODS + userId + "_" + goodsId, Constants.UserRbGoodsStatus.SUCCESS);
        //5.生成订单
        addOrder(userId, stockId, goodsVO);
        //释放锁
        redisTemplate.opsForValue().getOperations().delete(Constants.LOCK_PREFIX + goodsId);
    }

    private String addTempStock(String goodsId, String userId) throws Exception {
        QgGoodsTempStock tempStock = new QgGoodsTempStock();
        String stockId = IdWorker.getId();
        tempStock.setId(stockId);
        tempStock.setGoodsId(goodsId);
        tempStock.setUserId(userId);
        tempStock.setStatus(Constants.GoodsStatus.LOCK_STOCK);
        tempStock.setCreatedTime(new Date());
        goodsTempStockService.qdtxAddQgGoodsTempStock(tempStock);
        return stockId;
    }

    private void addOrder(String userId, String stockId, GoodsVO goodsVO) throws Exception {
        QgOrder order = new QgOrder();
        order.setId(IdWorker.getId());
        order.setUserId(userId);
        order.setStockId(stockId);
        order.setAmount(goodsVO.getPrice() * 1);
        order.setCreatedTime(new Date());
        order.setGoodsId(goodsVO.getId());
        order.setNum(1);
        order.setOrderNo(IdWorker.getId());
        order.setUpdatedTime(new Date());
        order.setStatus(Constants.PayStatus.NOPAY);
        qgOrderService.qdtxAddQgOrder(order);
    }
}
